//
//  FirstViewController.m
//  ocdemo
//
//  Created by JIENING ZHANG on 2019/4/5.
//  Copyright © 2019 JIENING ZHANG. All rights reserved.
//

#import "FirstViewController.h"

#import "DemoArrayLoop.h"
#import "DemoArraySort.h"
#import "DemoDicLoop.h"
#import "DemoDicSort.h"
#import "DemoSet.h"
#import "DemoString.h"
#import "DemoDateTime.h"
#import "DemoJson.h"
#import "DemoFile.h"
#import "DemoThread.h"
#import "DemoZip.h"
#import "DemoBranch.h"
#import "DemoOO.h"

#import "ExamBranch.h"
#import "ExamTread.h"
#import "ExamGraph.h"
#import "ExamPilstEqual.h"
#import "ExamClockView.h"
#import "DemoSnapshotScroll.h"

#import "AIBBeaconRegionAny.h"

#import "DemoTimmer.h"
#import "LZKButtonAddition.h"

#import "TBProcessChainTest.h"

#import <CoreLocation/CoreLocation.h>


@interface FirstViewController () <CLLocationManagerDelegate>

@property (nonatomic, strong) CLLocationManager *locationManager;
@property (nonatomic, strong) CLBeaconRegion    *beaconRegion;

@property (nonatomic, strong) UIButton          *timerDemoButton;
@property (nonatomic, strong) UIButton          *processChainDemoButton;
@property (nonatomic, strong) UIButton          *snapDemoButton;

@property (nonatomic, strong) ExamClockView     *clockView;
@end

@implementation FirstViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    
    /*
    NSString *testString = @"我们试试 emoji  表情😂😜👪 👏👏👏";
    NSDictionary *testDict = @{@"testkey":@{
                               @"anyKey": testString
                               }};
    NSError *error = nil;
    NSData *data = [NSJSONSerialization dataWithJSONObject:testDict options:0 error:&error];
    NSString *text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"text: %@", text);
    //*/
    
    [self makeLayout];
    
    logTSBegin(@"demo begin");
    
    /*
    logTS(@"DemoArrayLoop begin");
    [DemoArrayLoop demoLogic];
    
    logTS(@"DemoArraySort begin");
    [DemoArraySort demoLogic];
    
    logTS(@"DemoDicLoop begin");
    [DemoDicLoop demoLogic];
    
    logTS(@"DemoDicSort begin");
    [DemoDicSort demoLogic];
    
    logTS(@"DemoSet begin");
    [DemoSet demoLogic];
    
    logTS(@"DemoString begin");
    [DemoString demoLogic];
    
    logTS(@"DemoDateTime begin");
    [DemoDateTime demoLogic];
    
    logTS(@"DemoJson begin");
    [DemoJson demoLogic];
    
    logTS(@"DemoFile begin");
    [DemoFile demoLogic];
    
    logTS(@"DemoThread begin");
    [DemoThread demoLogic];
    
    logTS(@"DemoZip begin");
    [DemoZip demoLogic];

    logTS(@"DemoOO begin");
    [DemoOO demoLogic];
    
    logTS(@"DemoBranch begin");
    [DemoBranch demoLogic];
    //*/
    
    logTS(@"DemoString begin");
    [DemoString demoLogic];
    
    //[TBProcessChainTest demoLogic];
    //[TBProcessChainTest testLogic];
    //[DemoDicLoop demoTestEqual];
    
    //[DemoString demoRegLogic];
    
    //NSString *content = [[UIPasteboard generalPasteboard] string];
    
    
    //processGraphDemo();
    
    //[self demoSum];
    
    
    //[ExamBranch demoLogic];
    //[ExamTread demoLogic];
    //[ExamGraph demoLogic];
    //[ExamPilstEqual demoLogic];
    //[HanoiTower moveHanoiTowerFrom:0 to:2 numberFrom:3];
    
    //[HanoiTower moveHanoiTowerFrom:0 to:2 numberFrom:10];
    
    /*
    NSURL *testUrl = [NSURL URLWithString:@"https://content.tmall.com/wow/pegasus/subject/596/3362757155/10969066?ut_sk=1.Xc/0rnkxNLMDAMRYRaqetRBY_21380790_1589024729152.DingTalk.2688&pre_rn=76570e1e4c2be8d6caa9ed1be1ecb9a9&ttid=201200@taobao_iphone_9.7.0&isFull=true&suid=08713219-1481-454E-AA18-0F829CF45094&scm=20140655.sc_76570e1e4c2be8d6caa9ed1be1ecb9a9&q=qian&_xsearchRedirect=YES&sourceType=other&un=ca21105955c595e24fa79f0d87ab7c91&share_crt_v=1&cpp=1&shareurl=true&short_name=h.Vj83tWu&app=chrome&_tbScancodeApproach_=photo&share_token=OFhIPGhhPkg0OmvGMH84PWTT&actId=146870"];
    
    NSLog(@"testUrl = %@", testUrl);
    //*/
    
    _locationManager = [[CLLocationManager alloc]init];
    _locationManager.delegate = self;
    
    //[self driveClock];
    
    int end=100;
//    for (int index=0; index<end; ++index) {
//        if (index%3 == 0) {
//            if (index%5 == 0) {
//                NSLog(@"%d, FIZZ BUZZ", index);
//            } else {
//                NSLog(@"%d, FIZZ", index);
//            }
//        } else if (index%5 == 0) {
//            NSLog(@"%d, BUZZ", index);
//        } else {
//            NSLog(@"%d", index);
//        }
//    }
    
    
    for (int index=0; index<end; ++index) {
        NSLog(@"%d,%@ %@", index, (index%3 == 0)?@"FIZZ":@"", (index%5 == 0)?@"BUZZ":@"");
    }
}

-(void) driveClock {
    _clockView.clockDateTime = [NSDate date];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)),
                   dispatch_get_main_queue(),
                   ^{
        [self driveClock];
    });
}

-(void) demoSum {
    // 数组中有 10w 个元素
    // < 100 1024 = 100 ^ 10^10
    // 每个元素是整数，0 ~ 1024
    // 2^10
    // 100 * 2^20
    
    //累加
#define ArrLen 200000
    int arr[ArrLen];
    int *ptr = arr;
   
    for(int j=0; j<ArrLen; ++j){
        *ptr += (*ptr%1024);
        ++ptr;
    }
    
    // 常规方法累加
    CFTimeInterval curTs = CFAbsoluteTimeGetCurrent();
    int sum=0;
    ptr = arr;
    for(int j=0; j<ArrLen; ++j){
        sum += *ptr;
        ++ptr;
    }
    CFTimeInterval curTsEnd = CFAbsoluteTimeGetCurrent();
    
    NSLog(@"sum = %u, %.f(微秒)", sum, (curTsEnd - curTs)*1000000);
    
    // 常规方法累加
    curTs = CFAbsoluteTimeGetCurrent();
    sum=0;
    ptr = arr;
    for(int j=0; j<ArrLen; ++j){
        sum += arr[j];
    }
    curTsEnd = CFAbsoluteTimeGetCurrent();
    
    NSLog(@"sum = %u, %.f(微秒)", sum, (curTsEnd - curTs)*1000000);
    
    // 利用cpu流水线，for循环中的4条语句不相关，如此cpu流水线可以并行
    curTs = CFAbsoluteTimeGetCurrent();
    sum=0;
    int sub1=0;
    int sub2=0;
    int sub3=0;
    int sub4=0;
    for(int j=0; j<ArrLen; j+=4){
        sub1 += arr[j];
        sub2 += arr[j+1];
        sub3 += arr[j+2];
        sub4 += arr[j+3];
    }
    sum = sub1+sub2+sub3+sub4;
    curTsEnd = CFAbsoluteTimeGetCurrent();
    
    NSLog(@"sum = %u, %.f(微秒)", sum, (curTsEnd - curTs)*1000000);
    
    // 利用cpu流水线，for循环中的4条语句不相关，如此cpu流水线可以并行，指针累加，居然比数组寻址慢
    curTs = CFAbsoluteTimeGetCurrent();
    sum=0;
    int *ptr1 = arr;
    int *ptr2 = arr; ptr2 += ArrLen/4;
    int *ptr3 = arr; ptr3 += ArrLen/2;
    int *ptr4 = arr; ptr4 += ArrLen*3/4;
    
    sub1=0;
    sub2=0;
    sub3=0;
    sub4=0;
    curTs = CFAbsoluteTimeGetCurrent();
    for(int j=0; j<ArrLen; j+=4){
        sub1 += *ptr1; ++ptr1;
        sub2 += *ptr2; ++ptr2;
        sub3 += *ptr3; ++ptr3;
        sub4 += *ptr4; ++ptr4;
    }
    sum = sub1+sub2+sub3+sub4;
    curTsEnd = CFAbsoluteTimeGetCurrent();
    
    NSLog(@"sum = %u, %.f(微秒)", sum, (curTsEnd - curTs)*1000000);
}

-(void) makeLayout {
    // 行动按钮 top
    _timerDemoButton = [[UIButton alloc]initWithFrame:CGRectMake(30, 130, 120, 32)];
    _timerDemoButton.layer.masksToBounds = YES;
    _timerDemoButton.layer.cornerRadius = 8;
    _timerDemoButton.titleForStateNormal=@"timer demo";
    _timerDemoButton.titleColorForStateNormal = [UIColor whiteColor];
    _timerDemoButton.backgroundColorForStateNormal = [UIColor grayColor];
    [_timerDemoButton addTarget:self action:@selector(onTimerDemoButtonTouch:) forControlEvents:UIControlEventTouchUpInside];
    
    [self.view addSubview:_timerDemoButton];
    
    // 行动按钮 top
    _processChainDemoButton = [[UIButton alloc]initWithFrame:CGRectMake(30, 230, 120, 32)];
    _processChainDemoButton.layer.masksToBounds = YES;
    _processChainDemoButton.layer.cornerRadius = 8;
    _processChainDemoButton.titleForStateNormal=@"process Chain";
    _processChainDemoButton.titleColorForStateNormal = [UIColor whiteColor];
    _processChainDemoButton.backgroundColorForStateNormal = [UIColor grayColor];
    [_processChainDemoButton addTarget:self action:@selector(onProcessChainDemoButtonTouch:) forControlEvents:UIControlEventTouchUpInside];
    
    [self.view addSubview:_processChainDemoButton];
    
    // 行动按钮 top
    _snapDemoButton = [[UIButton alloc]initWithFrame:CGRectMake(30, 330, 120, 32)];
    _snapDemoButton.layer.masksToBounds = YES;
    _snapDemoButton.layer.cornerRadius = 8;
    _snapDemoButton.titleForStateNormal=@"snapShot";
    _snapDemoButton.titleColorForStateNormal = [UIColor whiteColor];
    _snapDemoButton.backgroundColorForStateNormal = [UIColor grayColor];
    [_snapDemoButton addTarget:self action:@selector(onSnapDemoButtonTouch:) forControlEvents:UIControlEventTouchUpInside];
    
    [self.view addSubview:_snapDemoButton];
    
    _clockView = [[ExamClockView alloc]initWithFrame:CGRectMake(30, 430, 150, 150)];
    _clockView.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:_clockView];
    
    //_clockView.clockDateTime = [NSDate date];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    return;
    
    // 模拟多线程同时 获取 定位权限授权状态，然后 定位权限授权状态 改变，看下是否会crash
    //[self locationStatusGT:@{@"index":@(0)}];
    //[self locationStatusMT:@{@"index":@(0)}];
    
    CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
    NSLog(@"viewDidAppear, status = %d", status);
    
    if( kCLAuthorizationStatusNotDetermined == status) {
        [_locationManager requestWhenInUseAuthorization];
    }
    
    //[_locationManager startUpdatingLocation];
    
    [self startScan];
}

- (void)onSnapDemoButtonTouch:(id)sender {
    DemoSnapshotScroll *demoSnapScroll = [[DemoSnapshotScroll alloc]init];
    [self.navigationController pushViewController:demoSnapScroll animated:YES];
}

- (void)onProcessChainDemoButtonTouch:(id)sender {
    [TBProcessChainTest demoLogic];
}

- (void)onTimerDemoButtonTouch:(id)sender {
    DemoTimmer *demoTimmer = [[DemoTimmer alloc]init];
    [self.navigationController pushViewController:demoTimmer animated:YES];
}

- (CLLocationManager *)locationManager {
    if (!_locationManager) {
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;
        _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    }
    return _locationManager;
}

- (CLBeaconRegion *)beaconRegion {
    
    if (!_beaconRegion) {
        
        //NSUUID *uuid4Region = [NSUUID new];
        //NSUUID *uuid4Region = [[NSUUID alloc] initWithUUIDString:BEACONUUID]
        
        //_beaconRegion = [[CLBeaconRegion alloc]initWithProximityUUID:uuid4Region identifier:@"KBCIndoor"];
        //_beaconRegion.notifyEntryStateOnDisplay = YES;
        
        _beaconRegion = [[AIBBeaconRegionAny alloc] initWithIdentifier:@"KBCNearby"];
        _beaconRegion.notifyOnExit = YES;
        _beaconRegion.notifyOnEntry = YES;
    }
    
    return _beaconRegion;
}

/*
- (void)locationStatusMT:(NSDictionary *)args {
    dispatch_block_t block = ^{

        CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
        NSLog(@"locationStatusMT, status = %d, %@", status, args[@"index"]);
        
        if( kCLAuthorizationStatusNotDetermined == status) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                NSNumber *indexNum = args[@"index"];
                [self locationStatusMT:@{@"index":@(indexNum.intValue + 1)}];
            });
        }
    };
    
    if (! [NSThread isMainThread]) {
        dispatch_async(dispatch_get_main_queue(), block);
    } else {
        block();
    }
}

- (void)locationStatusGT:(NSDictionary *)args {
    
    dispatch_block_t block = ^{
        //[self locationStatusMT];
        
        CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
        NSLog(@"locationStatusGT, status = %d, %@", status, args[@"index"]);
        
        if( kCLAuthorizationStatusNotDetermined == status) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                NSNumber *indexNum = args[@"index"];
                [self locationStatusGT:@{@"index":@(indexNum.intValue + 1)}];
            });
        }
        
    };
    
    if ([NSThread isMainThread]) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
    } else {
        block();
    }
}
//*/

- (void)locationManager:(CLLocationManager *)manager
     didUpdateLocations:(NSArray<CLLocation *> *)locations {
    
    CLLocation *recentLocation = [locations lastObject];
    
     NSLog(@"didUpdateLocations, lat=%.4f, lon=%.4f", recentLocation.coordinate.latitude, recentLocation.coordinate.longitude);
}

- (void)startScan {
    
    BOOL availableMonitor = [CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]];
    
    if (availableMonitor) {
        CLAuthorizationStatus authorizationStatus = [CLLocationManager authorizationStatus];
        
        switch (authorizationStatus) {
            case kCLAuthorizationStatusNotDetermined:
                NSLog(@"KBCNearbyIBeacon, 定位权限 未定");
                break;
            case kCLAuthorizationStatusRestricted:
            case kCLAuthorizationStatusDenied:
                NSLog(@"KBCNearbyIBeacon, 定位权限 受限");
                break;
            case kCLAuthorizationStatusAuthorizedAlways:
            case kCLAuthorizationStatusAuthorizedWhenInUse: {
                
                NSLog(@"KBCNearbyIBeacon, 定位权限ok, 开始扫描ibeacon");
                [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
                [self.locationManager startMonitoringForRegion:self.beaconRegion];
            }
                break;
        }
        
    } else {
        NSLog(@"KBCNearbyIBeacon, 设备不支持 CLBeaconRegion 区域检测");
    }
    
}

// Ranging成功对应回调函数
- (void)locationManager:(CLLocationManager *)manager
        didRangeBeacons:(NSArray<CLBeacon *> *)beacons
               inRegion:(CLBeaconRegion *)region {
    
    NSLog(@"beacons count: %lu", [beacons count]);
    
}

// Ranging有错误产生时的回调
- (void)locationManager:(CLLocationManager *)manager
rangingBeaconsDidFailForRegion:(CLBeaconRegion *)region
              withError:(NSError *)error {
    NSLog(@"KBCNearbyIBeacon, rangingBeaconsDidFailForRegion, %@", error);
}

@end
